'use strict'

/**
 * <--    还原前    -->
(function(t,a,b,c,d)
{
   console.log(a[0]+a[1]);
   console.log(b[0]-b[1]);
   console.log(c);
   console.log(d);
   t = 123;

})(5,[1,2],[5,3],6,-5);
 * 
 * <--    特点    -->
 * 1. 是立即调用函数表达式，此函数只用一次
 * 2. 可以直接将形参的引用替换为实参，这样便于阅读
 * 
 * <--    解决办法    -->
 * 通过CallExpression.arguments -- FunctionExpression.params建立形参与实参的关系，再替换，删除形参实参节点
 * 
 * <--    冗余判断    -->
 * 1. 要是iife（immediately invoked function expression）
 * 2. 该形参没有发生过变化
 * 3. 实参数据类型为字面量（或一元表达式），变量，数组
 * 
 * <--    还原后    -->
 (function (t) {
  console.log(1 + 2);
  console.log(5 - 3);
  console.log(6);
  console.log(-5);
  t = 123;
})(5);
 * 
 **/

const {parse} = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const t = require('@babel/types');
const generator = require('@babel/generator').default;

let code = `
(function(t,a,b,c,d)
{
   console.log(a[0]+a[1]);
   console.log(b[0]-b[1]);
   console.log(c);
   console.log(d);
   t = 123;

})(5,[1,2],[5,3],6,-5);`

const visitor = {
    CallExpression:{
        enter: function(path){
            // 非iife
            if(!t.isFunctionExpression(path.get('callee').node)){return}
            // 无实参
            if(!path.get('arguments').length){return}
            let i = 0;
            for(let paramPath of path.get('callee.params')){
                let argPath = path.get('arguments.'+i);
                let binding = paramPath.scope.getBinding(paramPath.node.name);
                // 无变化
                if(!binding || !binding.constant){
                    i += 1;
                    continue
                }

                // 值类型检查
                if (t.isUnaryExpression(argPath.node, {'operator': '-'}) || t.isUnaryExpression(argPath.node, {'operator': '+'})){
                    if(!t.isNumericLiteral(argPath.get('argument').node)){
                        i += 1;
                        continue
                    }
                }else if(!t.isLiteral(argPath.node) &&
                    !t.isArrayExpression(argPath.node) &&
                    !t.isIdentifier(argPath.node)){
                        i += 1;
                        return
                }

                // 引用替换
                for(let refPath of binding.referencePaths){
                    if(t.isMemberExpression(refPath.parent) && t.isArrayExpression(argPath.node)){
                        let membPath = refPath.parentPath;
                        let property = membPath.get('property').node.value;
                        console.log(membPath.toString(), property)
                        membPath.replaceInline(argPath.get('elements.'+property).node);
                    }
                    else{
                        refPath.replaceInline(argPath.node);
                    }
                }

                // 移除消解的形参实参，形参偏移量不再自增1
                paramPath.remove();
                argPath.remove();
            }
        },
    },
}

let ast = parse(code);
traverse(ast, visitor);
console.log(generator(ast).code);
